﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Happy.ExtentionMethods;
using Happy.StateManager.Configuration;
using Happy.StateManager.Configuration.Internal;

namespace Happy.StateManager
{
    /// <summary>
    /// 状态表格。
    /// </summary>
    public sealed class StateTable<TState, TOperation>
    {
        private readonly List<Transition<TState, TOperation>> _transitions = new List<Transition<TState, TOperation>>();
        private readonly Func<TState> _stateGetter;
        private readonly Action<TState> _stateSetter;

        /// <summary>
        /// 构造方法。
        /// </summary>
        public StateTable(Func<TState> stateGetter, Action<TState> stateSetter)
        {
            stateGetter.MustNotNull("stateGetter");
            stateSetter.MustNotNull("stateSetter");

            _stateGetter = stateGetter;
            _stateSetter = stateSetter;
        }

        /// <summary>
        /// 配置状态表格。
        /// </summary>
        public static IConfig<TState, TOperation> Config(Func<TState> stateGetter, Action<TState> stateSetter)
        {
            stateGetter.MustNotNull("stateGetter");
            stateSetter.MustNotNull("stateSetter");

            return new Config<TState, TOperation>(stateGetter, stateSetter);
        }

        /// <summary>
        /// 配置状态迁移。
        /// </summary>
        public StateTable<TState, TOperation> ConfigTransition(
            TState sourceState,
            TOperation operation,
            ICondition condition,
            TState targetState)
        {
            sourceState.MustNotNull("sourceState");
            operation.MustNotNull("operation");
            condition.MustNotNull("condition");
            targetState.MustNotNull("targetState");

            var transition = new Transition<TState, TOperation>(
                    sourceState,
                    operation,
                    condition,
                    targetState);

            _transitions.Add(transition);

            return this;
        }

        /// <summary>
        /// 使用<paramref name="operation"/>调度状态变换。
        /// </summary>
        public void Schedule(TOperation operation)
        {
            operation.MustNotNull("operation");

            var currentState = _stateGetter();
            var transition = _transitions
                .FirstOrDefault(x =>
                    x.SourceState.Equals(currentState)
                    &&
                    x.Operation.Equals(operation)
                    &&
                    x.Condition.IsSatisfied());

            if (transition == null)
            {
                throw new StateScheduleException(currentState, operation);
            }

            _stateSetter(transition.TargetState);
        }
    }
}
